package com.spider.silence.downloader;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.spider.silence.abstarct.downloader.AbstractLoginDownLoader;
import com.spider.silence.constant.Constant;
import com.spider.silence.utils.DateUtils;
import com.spider.silence.utils.FileUtils;
import com.spider.silence.utils.qzone.downloader.HttpClientDownloader;
import com.spider.silence.task.QZoneTask;
import com.spider.silence.task.manager.CommonTaskManager;
import com.spider.silence.utils.ChromeDriverUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.apache.log4j.Logger;
import org.jsoup.nodes.Document;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Site;

import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.utils.HttpConstant;

/**
 * Created by 夏茂轩 on 2017/1/10.
 */
public class QZoneDownLoader extends AbstractLoginDownLoader {
    private Logger logger = Logger.getLogger(QZoneDownLoader.class);
    private String qi;
    private String pwd;
    private int gtk;
    private int gtk2;
    private int idw;
    private String skey;
    private String p_skey;
    private Map<String,File> files=null;

    public Map<String,File> getFiles(){
        return files;
    }

    public QZoneDownLoader(String qi, String pwd) {
        this.qi = qi;
        this.pwd = pwd;
    }

    @Override
    protected HashSet<Cookie> login() {
        ChromeDriver driver = ChromeDriverUtils.getDriver();
        try {
            driver.get("http://qzone.qq.com/");
//            driver.manage().window().maximize();
            driver.switchTo().frame("login_frame").findElement(By.cssSelector("#switcher_plogin")).click();
            WebDriverWait loginFormWait = new WebDriverWait(driver, 20000);
            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
            while (true) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage(),e);
                    e.printStackTrace();
                    throw e;
                }
                if (driver.findElement(By.cssSelector("#u")).isEnabled()) {
                    loginFormWait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#u")))
                            .sendKeys(qi);
                    break;
                }
            }
            while (true) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage(),e);
                    e.printStackTrace();
                    throw e;
                }
                if (driver.findElement(By.cssSelector("#p")).isEnabled()) {
                    loginFormWait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#p")))
                            .sendKeys(pwd);
                    break;
                }
            }
            loginFormWait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#login_button"))).click();
            long start=System.currentTimeMillis();
            long end=System.currentTimeMillis();
            while (true&&(end-start)<20000) {
                end=System.currentTimeMillis();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage(),e);
                    e.printStackTrace();
                    throw e;
                }
                if (driver.getCurrentUrl().startsWith("http://user.qzone.qq.com/")) {
                    int flag=(int)Math.floor(Math.random()*1000);
                    if(flag<300){
                        try {
                            try {
                                Thread.sleep((int)Math.floor(8000));
                            } catch (InterruptedException e) {
                                logger.error(e.getMessage(),e);
                                e.printStackTrace();
                                throw e;
                            }
                            try {
                                Thread.sleep((int)Math.floor(5000));
                            } catch (InterruptedException e) {
                                logger.error(e.getMessage(),e);
                                e.printStackTrace();
                                throw e;
                            }
                        } catch (Exception e) {
                            logger.error(e.getMessage(),e);
                            e.printStackTrace();
                            throw e;
                        }
                    }
                    break;
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                logger.error(e.getMessage(),e);
                e.printStackTrace();
            }
            if(end-start<30000){
                cookies = (HashSet<Cookie>) driver.manage().getCookies();
                try {
                    skey=driver.manage().getCookieNamed("skey").getValue();
                    p_skey=driver.manage().getCookieNamed("p_skey").getValue();
                    gtk = getGTK(skey);
                    gtk2 = getGTK(p_skey);
                    idw = getIdw(driver.manage().getCookieNamed("skey").getValue());
                } catch (NullPointerException e) {
                    logger.error("登陆错误",e);
                    throw new Exception("登陆错误");
                }
            }else{
                logger.error(qi+":不能登录");
                throw new Exception(qi+":不能登录");
            }
            return  cookies;
        }catch(Exception e){
            logger.error(e.getMessage(),e);
            e.printStackTrace();
        } finally {
            driver.close();
            driver.quit();
        }
        return null;
    }

    /**
     * @author : 夏茂轩
     * @date : 2017/1/11 14:21
     * @description : 获取QQ空间的言论
     * @param target QQ号码
     * @param count 获取条数
     * @return
     * @throws JSONException
     */
    public JSONArray getQZItems(String target, int count) throws JSONException {
        files=new ConcurrentHashMap<>();
        JSONArray items =new JSONArray();
        String getUrl = "https://h5.qzone.qq.com/proxy/domain/taotao.qq.com/cgi-bin/emotion_cgi_msglist_v6?uin=%s&inCharset=utf-8&outCharset=utf-8&notice=0&sort=" +
                "0&pos=0&num=%s&code_version=1&format=json&need_private_comment=1&g_tk=%s";
        try {
            String url = "";
            if (p_skey!=null&&!p_skey.isEmpty()) {
                url = String.format(getUrl, new Object[]{target, count, getGTK(p_skey)});
            } else {
                url = String.format(getUrl, new Object[]{target, count, getGTK(skey)});
            }
            String html = getString(url);
            JSONObject object = JSON.parseObject(html);
            if(object.containsKey("msglist")){
                JSONArray msgList=object.getJSONArray("msglist");
                for (int i=0;i<msgList.size();i++){
                    try {
                        JSONObject msg=msgList.getJSONObject(i);
                        JSONObject msg_formatted=new JSONObject();
                        if(msg.containsKey("content")){//内容
                            msg_formatted.put("content",msg.getString("content"));
                        }
                        msg_formatted.put("publish_time", DateUtils.formatDateTime(new Date(msg.getLong("created_time")*1000)));
                        msg_formatted.put("publish_user_id",target);
                        msg_formatted.put("publish_user",msg.getString("name"));
                        msg_formatted.put("publish_user_photo",String.format("http://qlogo2.store.qq.com/qzone/%s/%s/100",new String[]{target,target}));
                        msg_formatted.put("spider_time",DateUtils.formatDateTime(new Date()));
                        msg_formatted.put("id",msg.getString("tid"));
                        msg_formatted.put("reply_count",msg.getIntValue("cmtnum"));
                        msg_formatted.put("url",String.format("https://user.qzone.qq.com/%s/311/%s",new String[]{target,msg.getString("tid")}));
                        if(msg.containsKey("video")){//视频
                            JSONArray videos=msg.getJSONArray("video");
                            JSONArray videos_formatted=new JSONArray();
                            for (int index=0;index<videos.size();index++){
                                JSONObject video=videos.getJSONObject(index);
                                if(video.containsKey("url3")){
                                    String video_url=video.getString("url3")+"?rf=mood_app";
                                    videos_formatted.add(video_url);
                                }
                            }
                            msg_formatted.put("video_urls",videos_formatted);
                        }
                        if(msg.containsKey("pic")){//图片
                            JSONArray pics=msg.getJSONArray("pic");
                            JSONArray pics_formatted=new JSONArray();
                            for (int index=0;index<pics.size();index++){
                                JSONObject pic=pics.getJSONObject(index);
                                if(pic.containsKey("url3")){
                                    String img_url=pic.getString("url3")+"?rf=mood_app";
                                    pics_formatted.add(img_url);
                                }
                            }
                            msg_formatted.put("img_urls",pics_formatted);
                        }
                        String fileName="QZone_"+msg.getLong("created_time")*1000+"_"+target+"_"+msg.getString("tid");
                        System.out.println(fileName+"@@@@@@");
                        String publishDate=DateUtils.formatDate(new Date(msg.getLong("created_time")*1000));
                        String speechesId = "QQ空间_speeches_" + publishDate + "_" + fileName;
                        File file = FileUtils.createTempFile(speechesId + "_pageNo_1", msg.toJSONString());
                        files.put(speechesId + "_pageNo_1", file);
                        if(msg.containsKey("commentlist")){//回复
                            JSONArray commentlist=msg.getJSONArray("commentlist");
                            JSONArray commentlist_formatted=new JSONArray();
                            if(commentlist!=null){
                                for (int index=0;index<commentlist.size();index++){
                                    JSONObject reply=commentlist.getJSONObject(index);
                                    JSONObject reply_format=new JSONObject();
                                    //TODO 格式化回复
                                    reply_format.put("content",reply.getString("content"));
                                    reply_format.put("create_time",DateUtils.formatDateTime(new Date(reply.getLong("create_time")*1000)));
                                    reply_format.put("publish_user_id",reply.getString("uin"));
                                    reply_format.put("publish_user",reply.getString("name"));
                                    reply_format.put("publish_user_photo",String.format("http://qlogo2.store.qq.com/qzone/%s/%s/100",new String[]{reply.getString("uin"),reply.getString("uin")}));
                                    reply_format.put("parent_id",msg.getString("tid"));
                                    commentlist_formatted.add(reply_format);
                                }
                            }
                            if(commentlist_formatted.size()>0){
                                msg_formatted.put("reply_nodes",commentlist_formatted);
                            }
                        }
                        JSONObject data=new JSONObject();
                        data.put("data",msg_formatted);
                        items.add(data);
                    } catch (Exception e) {
                        e.printStackTrace();
                        continue;
                    }
                }
            }
            return items;
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            e.printStackTrace();
        } finally {
            try {
                Thread.sleep((int) Math.random() * 2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return items;
    }

    /**
     * @author  夏茂轩
     * @date  2017/1/11 14:22
     * @description  生成QQ空间爬虫任务
     */
    public void generateTask(){
        JSONObject object = queryQQInfo("");
        JSONArray array =object.getJSONObject("result").getJSONObject("buddy").getJSONArray("info_list");
        for(int i=0;i<array.size();i++){
            QZoneTask task =new QZoneTask(array.getJSONObject(i).getString("uin"));
            try {
                CommonTaskManager.add("QZone",task);
            } catch (Exception e) {
                logger.error(e.getMessage(),e);
                e.printStackTrace();
            }
        }
    }

    /**
     * @author  夏茂轩
     * @date  2017/1/11 14:22
     * @description  查询QQ信息
     * @param target QQ号码
     * @return
     * @throws JSONException
     */
    public JSONObject queryQQInfo(String target) throws JSONException {
        try {
            String queryUrl = "http://cgi.find.qq.com/qqfind/buddy/search_v3";
            Map<String,String> param= Maps.newHashMap();
            param.put("num", 20 + "");
            param.put("page", "0");
            param.put("sessionid", "0");
            param.put("keyword", target);
            param.put("agerg", "0");
            param.put("sex", "0");
            param.put("video", "0");
            param.put("city", "1");
            param.put("country", "1");
            param.put("province", "51");
            param.put("district", "0");
            param.put("hprovince", "0");
            param.put("hcity", "0");
            param.put("hdistrict", "0");
            param.put("online", "1");
            param.put("ldw", idw + "");
            String html = post(queryUrl,param).text();
            return JSONObject.parseObject(html);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            e.printStackTrace();
        } finally {
            try {
                Thread.sleep((int) Math.random() * 2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * @author 夏茂轩
     * @date  2017/1/11 14:23
     * @description 计算GTK参数
     * @param str 参数
     * @return
     */
    public int getGTK(String str) {
        int hash = 5381;
        for (int i = 0, len = str.length(); i < len; ++i)
            hash += (hash << 5) + (int) str.charAt(i);
        return hash & 2147483647;
    }

    /**
     * @author 夏茂轩
     * @date 2017/1/11 14:24
     * @description 计算IDW参数
     * @param key 参数
     * @return
     */
    public int getIdw(String key) {
        String e = key;
        int n = 5381;
        for (int r = 0, i = e.length(); r < i; ++r) {
            int aa = (int) e.charAt(r);
            n += (n << 5) + aa;
        }
        return n & 2147483647;
    }

    public int getGtk() {
        return gtk;
    }

    public void setGtk(int gtk) {
        this.gtk = gtk;
    }

    public int getIdw() {
        return idw;
    }

    public void setIdw(int idw) {
        this.idw = idw;
    }


    @Override
    public String getString(String url) throws  Exception{
        return getString(url,null);
    }

    @Override
    public String getString(String url,final String proxy)throws Exception {
        request.setUrl(url);
        task=new Task() {
            @Override
            public String getUUID() {
                return UUID.randomUUID().toString();
            }
            @Override
            public Site getSite() {
                Site site = new Site();
                site.setUserAgent(Constant.HTTP_USER_AGENT);
                site.setRetryTimes(Constant.HTTP_RETRY_TIMES);
                site.setCycleRetryTimes(Constant.HTTP_RETRY_TIMES);
                site.setTimeOut(Constant.HTTP_TIME_OUT);
                site.setAcceptStatCode(Sets.newHashSet(403,200));
                if(headers!=null){
                    for(Map.Entry<String, String> entry:headers.entrySet()){
                        site.addHeader(entry.getKey(),entry.getValue());
                    }
                }
                if(cookies!=null){
                    for (Cookie cookie : cookies) {
                        site.addCookie(cookie.getDomain(), cookie.getName(), cookie.getValue());
                    }
                }
                return site;
            }
        };
        return downloader.download(request,task).getRawText();
    }


    @Override
    public Document post(String url) throws Exception {
        return post(url,null,null);
    }

    @Override
    public Document post(String url, String proxy) throws Exception {
        return post(url,null,proxy);
    }
    @Override
    public Document post(String url, boolean isProxy) throws Exception {
        return post(url,null,isProxy);
    }

    @Override
    public Document post(String url, Map<String, String> params) throws Exception {
        return post(url,params,null);
    }

    @Override
    public Document post(String url, final Map<String, String> params, final String proxy) throws Exception {
        task=new Task() {
            @Override
            public String getUUID() {
                return UUID.randomUUID().toString();
            }
            @Override
            public Site getSite() {
                Site site = new Site();
                site.setUserAgent(Constant.HTTP_USER_AGENT);
                site.setRetryTimes(Constant.HTTP_RETRY_TIMES);
                site.setTimeOut(Constant.HTTP_TIME_OUT);
                site.setCycleRetryTimes(Constant.HTTP_RETRY_TIMES);
                if(headers!=null){
                    for(Map.Entry<String, String> entry:headers.entrySet()){
                        site.addHeader(entry.getKey(),entry.getValue());
                    }
                }
                if(cookies!=null){
                    for (Cookie cookie : cookies) {
                        site.addCookie(cookie.getDomain(), cookie.getName(), cookie.getValue());
                    }
                }
                return site;
            }
        };
        Request request2 = new Request(url);
        NameValuePair[] values = new NameValuePair[params.size()];
        if(params!=null){
            int i=0;
            for(Map.Entry<String, String> entry:params.entrySet()){
                values[i] = new BasicNameValuePair(entry.getKey(),entry.getValue());
                i++;
            }
        };
        Map nameValuePair = new HashMap();
        nameValuePair.put("nameValuePair", values);
        request2.setExtras(nameValuePair);
        request2.setMethod(HttpConstant.Method.POST);
        return downloader.download(request2,task).getHtml().getDocument();

    }
    @Override
    public Document post(String url, Map<String,String> params, final boolean isProxy)  throws Exception{
        task=new Task() {
            @Override
            public String getUUID() {
                return UUID.randomUUID().toString();
            }
            @Override
            public Site getSite() {
                Site site = new Site();
                site.setUserAgent(Constant.HTTP_USER_AGENT);
                site.setRetryTimes(Constant.HTTP_RETRY_TIMES);
                site.setTimeOut(Constant.HTTP_TIME_OUT);
                site.setCycleRetryTimes(Constant.HTTP_RETRY_TIMES);
                if(headers!=null){
                    for(Map.Entry<String, String> entry:headers.entrySet()){
                        site.addHeader(entry.getKey(),entry.getValue());
                    }
                }
                if(cookies!=null){
                    for (Cookie cookie : cookies) {
                        site.addCookie(cookie.getDomain(), cookie.getName(), cookie.getValue());
                    }
                }
                return site;
            }
        };
        Request request2 = new Request(url);
        NameValuePair[] values = new NameValuePair[params.size()];
        if(params!=null){
            int i=0;
            for(Map.Entry<String, String> entry:params.entrySet()){
                values[i] = new BasicNameValuePair(entry.getKey(),entry.getValue());
                i++;
            }
        };
        Map nameValuePair = new HashMap();
        nameValuePair.put("nameValuePair", values);
        request2.setExtras(nameValuePair);
        request2.setMethod(HttpConstant.Method.POST);
        return downloader.download(request2,task).getHtml().getDocument();
    }

}
